/* 
 *	Copyright (C) 2009-2010 miaohua
 *	http://code.google.com/p/lrcshower/
 *
 *  This Program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  This Program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *  http://www.gnu.org/copyleft/gpl.html
 *
 */

#include "StdAfx.h"
#include <string>
#include <numeric>
#include <algorithm>
#include "TypeDef.h"
#include "PlayList.h"

void OnePlayList::GenRandIdx()
{
     if( m_SongList.size() == 0 ) return;
     // Get random play index
     m_RandList.resize(m_SongList.size());
     m_RandIdxList.resize(m_SongList.size());
     int Size = m_RandList.size();
     for( int i = 0; i < Size; ++i )
          m_RandList[i] = i;    
     random_shuffle(m_RandList.begin(), m_RandList.end());
     // Initialize the random index array
     for( int i = 0; i < Size; ++i )
          m_RandIdxList[m_RandList[i]] = i;
}

bool OnePlayList::IsSongValidate(unsigned int SongIdx)const
{
     if( SongIdx == -1 ) 
         SongIdx = m_SelSongIdx;

     if( SongIdx >= m_SongList.size() )
         return 0;

     return m_SongList[SongIdx].IsValidate();
}

int OnePlayList::GetIndex(unsigned int SongIdx)const
{
     if( SongIdx == -1 ) 
         SongIdx = m_SelSongIdx;

     if( SongIdx >= m_SongList.size() )
         return 0;

     return m_SongList[SongIdx].GetIndex();
}

REFERENCE_TIME OnePlayList::GetDura(unsigned int SongIdx)const
{
     if( SongIdx == -1 ) 
         SongIdx = m_SelSongIdx;

     if( SongIdx >= m_SongList.size() )
         return 0;

     return m_SongList[SongIdx].GetDura();
}

tstring OnePlayList::GetNextProp(unsigned int SongIdx)
{
     if( SongIdx == -1 )
         SongIdx = m_SelSongIdx;

     if( SongIdx >= m_SongList.size() )
         return _T("");
    
     return m_SongList[SongIdx].GetNextProp();
}

tstring OnePlayList::GetLabel(unsigned int SongIdx)const
{
     if( SongIdx == -1 )
         SongIdx = m_SelSongIdx;

     if( SongIdx >= m_SongList.size() )
         return _T("");
    
     return m_SongList[SongIdx].GetLabel();
}

tstring OnePlayList::GetFullPath(unsigned int SongIdx)const
{
     if( SongIdx == -1 )
         SongIdx = m_SelSongIdx;

     if( SongIdx >= m_SongList.size() )
         return _T("");
    
     return m_SongList[SongIdx].GetFullPath();
}

tstring OnePlayList::GetSongName(unsigned int SongIdx)const 
{
     if( SongIdx == -1 )
         SongIdx = m_SelSongIdx;

     if( SongIdx >= m_SongList.size() )
         return _T("");
    
     return m_SongList[SongIdx].GetName();
}

tstring OnePlayList::GetSingerName(unsigned int SongIdx)const
{
     if( SongIdx == -1 )
         SongIdx = m_SelSongIdx;

     if( SongIdx >= m_SongList.size() )
         return _T("");
    
     return m_SongList[SongIdx].GetSinger();
}

tstring OnePlayList::GetSongTips(unsigned int SongIdx)const
{
     if( SongIdx == -1 )
         SongIdx = m_SelSongIdx;

     if( SongIdx >= m_SongList.size() )
         return _T("");
    
     return m_SongList[SongIdx].GetTips();
}

int OnePlayList::MoveOneSong(int SrcIdx, int DstIdx)
{
     // Check index's validation
     if( SrcIdx < 0 || SrcIdx >= m_SongList.size() ) return -1;
     if( SrcIdx == DstIdx ) return DstIdx;

     // Do move
     int Pos = -1;
     if( DstIdx < 0 || DstIdx >= m_SongList.size() ) 
     {
         // Change position, erase original one
         m_SongList.push_back(m_SongList[SrcIdx]);
         m_SongList.erase(m_SongList.begin()+SrcIdx);
         // The real position
         Pos = m_SongList.size()-1;
     } else {
         // Change position
         m_SongList.insert(m_SongList.begin()+DstIdx, m_SongList[SrcIdx]);
         m_SongList.erase(m_SongList.begin()+SrcIdx);
         // The real position
         Pos = DstIdx;
     }

     // If add before selected song, increase m_SelSongIdx by one;
     if( Pos <= m_SelSongIdx ) ++ m_SelSongIdx;
     
     // Random index
     GenRandIdx();

     return Pos;
}

int OnePlayList::AddOneSong(const tstring & SongFullPath, int Pos)
{
     // Read current song's property
     SongProp Song(SongFullPath);
     Song.GetSongProperty();

     // Insert into current playlist 
     int Index = -1;
     if( Pos < 0 || Pos >= m_SongList.size() )
     {
         m_SongList.push_back(Song);
         Index = m_SongList.size()-1;
     } else {
         m_SongList.insert(m_SongList.end()+Pos, Song);
         Index = Pos;
     }
     // If add before selected song, increase m_SelSongIdx by one;
     if( Index <= m_SelSongIdx ) ++ m_SelSongIdx;

     // Random index
     GenRandIdx();

     return Index;
}

int OnePlayList::GetPrevSongIdx(int PlayMode)
{
    // If whole play list is invalidate, just return nothing
    // If selected song index is invalidate, just return nothing
    if( !IsValidate() || m_SelSongIdx == -1 )
        return -1;

    // Get next validate song in current play list
    int Size = m_SongList.size();
    int PrevSongIdx = -1;

    if( PlayMode&RAND )
    {
        int CurIdx = m_RandList[m_SelSongIdx];
        for( int i = CurIdx-1; i >= 0; --i )
        {
             int SongIdx = m_RandIdxList[i];
             if( m_SongList[SongIdx].IsValidate() )
             {
                 PrevSongIdx = SongIdx;
                 break;
             }
        }

        if( (PlayMode&LOOP) && PrevSongIdx==-1 )
        {
            for( int i = Size-1; i > CurIdx; --i )
            {
                 int SongIdx = m_RandIdxList[i];
                 if( m_SongList[SongIdx].IsValidate() )
                 {
                     PrevSongIdx = SongIdx;
                     break;
                 }
            }
        }
    } else {
        if( PlayMode&SEQ )
        {
            for( int i = m_SelSongIdx-1; i >= 0; --i )
                 if( m_SongList[i].IsValidate() )
                 {
                     PrevSongIdx = i;
                     break;
                 }
        }

        if( (PlayMode&LOOP) && PrevSongIdx==-1 )
        {
            for( int i = Size-1; i >= m_SelSongIdx+1; --i )
                 if( m_SongList[i].IsValidate() )
                 {
                     PrevSongIdx = i;
                     break;
                 }
        }
    }

    return PrevSongIdx;
}

int OnePlayList::GetNextSongIdx(int PlayMode)
{
    // If whole play list is invalidate, just return nothing
    // If selected song index is invalidate, just return nothing
    if( !IsValidate() || m_SelSongIdx == -1 )
        return -1;

    // Get next validate song in current play list
    int Size = m_SongList.size();
    int NextSongIdx = -1;

    if( PlayMode&RAND )
    {
        int CurIdx = m_RandList[m_SelSongIdx];
        for( int i = CurIdx+1; i < Size; ++i )
        {
             int SongIdx = m_RandIdxList[i];
             if( m_SongList[SongIdx].IsValidate() )
             {
                 NextSongIdx = SongIdx;
                 break;
             }
        }

        if( (PlayMode&LOOP) && NextSongIdx==-1 )
        {
            for( int i = 0; i < CurIdx; ++i )
            {
                 int SongIdx = m_RandIdxList[i];
                 if( m_SongList[SongIdx].IsValidate() )
                 {
                     NextSongIdx = SongIdx;
                     break;
                 }
            }
        }
    } else {
        if( PlayMode&SEQ )
        {
            for( int i = m_SelSongIdx+1; i < Size; ++i )
                 if( m_SongList[i].IsValidate() )
                 {
                     NextSongIdx = i;
                     break;
                 }
        }

        if( (PlayMode&LOOP) && NextSongIdx==-1 )
        {
            for( int i = 0; i < m_SelSongIdx; ++i )
                 if( m_SongList[i].IsValidate() )
                 {
                     NextSongIdx = i;
                     break;
                 }
        }
    }

    return NextSongIdx;
}

int OnePlayList::GetSelSongIdx()const
{
     return m_SelSongIdx;
}
   
void OnePlayList::SetSelSongIdx(int SongIdx)
{
     m_SelSongIdx = SongIdx;
}

void OnePlayList::GetSongProp()
{  
     unsigned int Size = m_SongList.size();
     for( unsigned int i = 0; i < Size; ++i )
          m_SongList[i].GetSongProperty();
}
